package com.evil.application.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.account.api.RemoteUserEnterpriseService;
import com.evil.application.api.RemoteApplicationViewService;
import com.evil.application.mapper.ApplicationInfoMapper;
import com.evil.application.mapper.ApplicationViewMapper;
import com.evil.application.pojo.dto.CopyApplicationDTO;
import com.evil.application.pojo.dto.button.ButtonInfoRespDTO;
import com.evil.application.pojo.dto.button.CopyButtonReqDTO;
import com.evil.application.pojo.dto.button.ModifyButtonsReqDTO;
import com.evil.application.pojo.dto.view.ApplicationViewDTO;
import com.evil.application.pojo.dto.view.ApplicationViewReqDTO;
import com.evil.application.pojo.dto.view.ApplicationViewRespDTO;
import com.evil.application.pojo.dto.view.ModifyApplicationViewReqDTO;
import com.evil.application.pojo.dto.view.config.OtherConfigDTO;
import com.evil.application.pojo.dto.view.config.ViewFilterConfigDTO;
import com.evil.application.pojo.dto.view.config.filter.CopyFilterReqDTO;
import com.evil.application.pojo.dto.view.config.filter.FilterGroupDTO;
import com.evil.application.pojo.dto.view.config.filter.FilterSourceDTO;
import com.evil.application.pojo.dto.view.config.filter.ModifyFilterReqDTO;
import com.evil.application.pojo.entity.ApplicationInfo;
import com.evil.application.pojo.entity.ApplicationView;
import com.evil.application.service.ApplicationButtonService;
import com.evil.application.service.ApplicationFilterGroupService;
import com.evil.application.service.ApplicationPermissionService;
import com.evil.application.service.ApplicationViewService;
import com.evil.application.util.ApplicationUtil;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.application.dto.button.ButtonSourceDTO;
import com.evil.common.application.dto.permission.app.AppPermissionSourceDTO;
import com.evil.common.application.enums.ApplicationSourceTypeEnum;
import com.evil.common.application.enums.ApplicationVersionEnum;
import com.evil.common.application.enums.button.ButtonSourceTypeEnum;
import com.evil.common.application.enums.filter.FilterSourceTypeEnum;
import com.evil.common.application.enums.view.ApplicationViewTypeEnum;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 应用视图配置表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class ApplicationViewServiceImpl extends ServiceImpl<ApplicationViewMapper, ApplicationView>
        implements ApplicationViewService, RemoteApplicationViewService {

    private final LoginUtil loginUtil;

    private final ApplicationInfoMapper applicationInfoMapper;

    private final ApplicationButtonService applicationButtonService;

    private final ApplicationFilterGroupService applicationFilterGroupService;

    private final ApplicationPermissionService applicationPermissionService;

    private final RemoteUserEnterpriseService remoteUserEnterpriseService;

    private final ApplicationLogServiceImpl applicationLogService;

    /**
     * 删除应用所有视图
     *
     * @param applicationInfo applicationInfo
     */
    @Override
    public void deleteByApp(ApplicationInfo applicationInfo) {
        List<ApplicationView> views = this.baseMapper.findAllByAppIdId(applicationInfo.getApplicationId(), true);
        views.forEach(v -> v.setIsDeleted(SwitchEnum.YES.getId()));
        applicationLogService.saveAndCheck(this.baseMapper, ApplicationView::getApplicationViewId, views);
    }

    /**
     * 复制应用所有视图
     *
     * @param copyApplicationDTO copyApplicationDTO
     */
    @Override
    public void copyByApp(CopyApplicationDTO copyApplicationDTO) {
        ApplicationInfo source = copyApplicationDTO.getSource();
        ApplicationInfo target = copyApplicationDTO.getTarget();

        List<ApplicationView> sourceViews = this.baseMapper.findAllByAppIdId(source.getApplicationId(), true);
        List<ApplicationView> targetViews = this.baseMapper.findAllByAppIdId(target.getApplicationId(), true);
        // 复制视图
        this.copyViews(target.getEnterpriseId(), sourceViews, targetViews, null, false);
    }

    /**
     * 发布应用所有视图
     *
     * @param applicationInfo applicationInfo
     */
    @Override
    public void publishView(ApplicationInfo applicationInfo) {
        this.replaceView(applicationInfo, true);
    }

    /**
     * 还原应用所有视图
     *
     * @param applicationInfo applicationInfo
     */
    @Override
    public void restoreView(ApplicationInfo applicationInfo) {
        this.replaceView(applicationInfo, false);
    }

    /**
     * 应用视图详情
     *
     * @param applicationViewReqDTO applicationViewReqDTO
     * @return Map
     */
    @Override
    public ApplicationViewRespDTO viewInfo(ApplicationViewReqDTO applicationViewReqDTO) {
        ApplicationVersionEnum versionEnum = ApplicationVersionEnum.findById(applicationViewReqDTO.getApplicationVersion());

        ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(applicationViewReqDTO.getApplicationKey());
        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());

        // 检查登录用户是否有权限
        applicationPermissionService.loginUserHasPermission(
                applicationInfo.getEnterpriseId(),
                applicationInfo.getPermissionStatus(),
                new AppPermissionSourceDTO(ApplicationSourceTypeEnum.APPLICATION, applicationInfo.getApplicationId()),
                false);

        List<ApplicationViewDTO> views = this.baseMapper.findByAppIdId(applicationInfo.getApplicationId(), versionEnum.getId()).stream()
                .map(applicationView -> {
                    ApplicationViewDTO view = new ApplicationViewDTO(applicationView);
                    if (ApplicationViewTypeEnum.FILTER.getId() == applicationView.getViewType()) {
                        List<FilterGroupDTO> filterGroupDTOS = applicationFilterGroupService.findBySource(
                                new FilterSourceDTO(FilterSourceTypeEnum.FILTER_VIEW_FILTER, applicationView.getApplicationViewId()));
                        view.getViewConfig().setFilterConfig(new ViewFilterConfigDTO(filterGroupDTOS));
                    }
                    OtherConfigDTO otherConfig = view.getOtherConfig();

                    // 视图按钮
                    ButtonSourceDTO source = new ButtonSourceDTO(ButtonSourceTypeEnum.APPLICATION_VIEW_BUTTON,
                            applicationView.getApplicationViewId(), applicationView.getApplicationVersion());
                    List<ButtonInfoRespDTO> buttons = applicationButtonService.findBySource(source);
                    otherConfig.setCustomButtons(buttons);

                    return view;
                })
                .collect(Collectors.toList());

        ApplicationViewRespDTO applicationViewRespDTO = new ApplicationViewRespDTO();
        applicationViewRespDTO.setViews(views);
        return applicationViewRespDTO;
    }

    /**
     * 编辑应用视图
     *
     * @param modifyApplicationViewReqDTO modifyApplicationViewReqDTO
     */
    @Override
    public void modify(ModifyApplicationViewReqDTO modifyApplicationViewReqDTO) {
        ApplicationVersionEnum versionEnum = ApplicationVersionEnum.findById(modifyApplicationViewReqDTO.getApplicationVersion());

        if (ApplicationVersionEnum.RELEASE_VERSION.getId() == versionEnum.getId()) {
            throw new BusinessException(RCodeEnum.ERROR_PARAMETER, "不允许编辑发布版视图");
        }

        ApplicationInfo app = applicationInfoMapper.findByKey(modifyApplicationViewReqDTO.getApplicationKey());
        // 检查企业
        loginUtil.checkEnterpriseId(app.getEnterpriseId());

        // 检查是否是管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        // 获取已有视图
        List<ApplicationView> applicationViews = this.baseMapper.findByAppIdId(app.getApplicationId(), versionEnum.getId());
        Map<String, ApplicationView> applicationViewMap = StreamUtil.toMapK(applicationViews, ApplicationView::getViewKey);

        // 获取参数视图
        Map<String, ApplicationViewDTO> viewMap = StreamUtil.toMapFK(modifyApplicationViewReqDTO.getViews(),
                e -> StringUtils.isNotBlank(e.getViewKey()), ApplicationViewDTO::getViewKey);

        // 新增、修改
        modifyApplicationViewReqDTO.getViews().forEach(view -> {
            // 检查属性
            view.checkProp();

            ApplicationView applicationView;
            if (StringUtils.isNotBlank(view.getViewKey())) {
                if (!applicationViewMap.containsKey(view.getViewKey())) {
                    throw new BusinessException(RCodeEnum.APPLICATION_VIEW_NOT_EXIST);
                }
                applicationView = applicationViewMap.get(view.getViewKey());
            } else {
                applicationView = new ApplicationView();
                applicationView.setEnterpriseId(app.getEnterpriseId());
                applicationView.setViewKey(ApplicationUtil.generateKey(key -> this.baseMapper.isExistByKey(key).isPresent()));
                applicationView.setApplicationId(app.getApplicationId());
                applicationView.setApplicationVersion(versionEnum.getId());
            }
            // 复制属性
            view.copyProp(applicationView);
            applicationLogService.saveAndCheck(this.baseMapper, ApplicationView::getApplicationViewId, applicationView);

            // 应用视图按钮
            ModifyButtonsReqDTO modifyButtonsReqDTO = new ModifyButtonsReqDTO();
            modifyButtonsReqDTO.setSource(new ButtonSourceDTO(ButtonSourceTypeEnum.APPLICATION_VIEW_BUTTON,
                    applicationView.getApplicationViewId(), applicationView.getApplicationVersion()));
            modifyButtonsReqDTO.setButtons(StreamUtil.transListT(view.getOtherConfig().getCustomButtons(), e -> e));
            applicationButtonService.saveButtons(modifyButtonsReqDTO);

            ModifyFilterReqDTO modifyFilterReqDTO = null;
            // 筛选视图-特殊处理
            if (ApplicationViewTypeEnum.FILTER.getId() == view.getViewType()) {
                modifyFilterReqDTO = new ModifyFilterReqDTO(FilterSourceTypeEnum.FILTER_VIEW_FILTER, app.getEnterpriseId(), applicationView.getApplicationViewId());
                modifyFilterReqDTO.setFilters(view.getViewConfig().getFilterConfig().getFilterConfig());

                // 需要置空
                view.getViewConfig().setFilterConfig(new ViewFilterConfigDTO());
            }

            if (Objects.nonNull(modifyFilterReqDTO)) {
                applicationFilterGroupService.saveFilter(modifyFilterReqDTO);
            }
        });

        // 删除
        List<ApplicationView> viewDeleted = StreamUtil.peekF(applicationViews,
                e -> !viewMap.containsKey(e.getViewKey()), e -> e.setIsDeleted(SwitchEnum.YES.getId()));
        applicationLogService.saveAndCheck(this.baseMapper, ApplicationView::getApplicationViewId, viewDeleted);
    }

    /**
     * 替换版本视图
     *
     * @param applicationInfo applicationInfo
     * @param isPublish       isPublish
     */
    private void replaceView(ApplicationInfo applicationInfo, boolean isPublish) {
        // 发布版
        int releaseVersion = ApplicationVersionEnum.RELEASE_VERSION.getId();
        // 设计版
        int designVersion = ApplicationVersionEnum.DESIGN_VERSION.getId();
        List<ApplicationView> releaseViews = new ArrayList<>();
        List<ApplicationView> designViews = new ArrayList<>();

        List<ApplicationView> views = this.baseMapper.findAllByAppIdId(applicationInfo.getApplicationId(), true);
        views.forEach(view -> {
            if (releaseVersion == view.getApplicationVersion()) {
                releaseViews.add(view);
            } else if (designVersion == view.getApplicationVersion()) {
                designViews.add(view);
            }
        });

        if (isPublish) {
            // 发布
            this.copyViews(applicationInfo.getEnterpriseId(), designViews, releaseViews, releaseVersion, true);
        } else {
            // 还原
            this.copyViews(applicationInfo.getEnterpriseId(), releaseViews, designViews, designVersion, true);
        }
    }

    /**
     * 复制视图
     *
     * @param source       复制源
     * @param target       复制目标
     * @param updateSource 是否更新源id
     */
    private void copyViews(Long enterpriseId, List<ApplicationView> source, List<ApplicationView> target, Integer applicationVersion, boolean updateSource) {
        Map<Long, ApplicationView> targetSourceViewMap = StreamUtil.toMapK(target, ApplicationView::getSourceViewId);

        // 记录有修改
        List<Long> modifyIds = new ArrayList<>();
        source.forEach(view -> {
            ApplicationView copyView;
            if (targetSourceViewMap.containsKey(view.getApplicationViewId())) {
                copyView = targetSourceViewMap.get(view.getApplicationViewId());
                modifyIds.add(copyView.getApplicationViewId());
            } else {
                copyView = new ApplicationView();
                copyView.setEnterpriseId(enterpriseId);
                copyView.setViewKey(ApplicationUtil.generateKey(key -> this.baseMapper.isExistByKey(key).isPresent()));
                copyView.setApplicationId(view.getApplicationId());
                // 是否指定目标 版本号
                copyView.setApplicationVersion(ObjectUtil.defaultIfNull(applicationVersion, view.getApplicationVersion()));
            }
            // 复制属性
            this.copyViewProp(view, copyView);
            copyView.setSourceViewId(view.getApplicationViewId());

            applicationLogService.saveAndCheck(this.baseMapper, ApplicationView::getApplicationViewId, copyView);

            // 更新源信息
            if (updateSource && !view.getSourceViewId().equals(copyView.getApplicationViewId())) {
                view.setSourceViewId(copyView.getApplicationViewId());
                applicationLogService.saveAndCheck(this.baseMapper, ApplicationView::getApplicationViewId, view);
            }

            // 筛选视图-复制筛选
            if (ApplicationViewTypeEnum.FILTER.getId() == view.getViewType()) {
                Long sourceId = view.getApplicationViewId();
                Long targetId = copyView.getApplicationViewId();
                applicationFilterGroupService.copyFilter(new CopyFilterReqDTO(FilterSourceTypeEnum.FILTER_VIEW_FILTER, enterpriseId, sourceId, targetId, updateSource));
            }

            // 复制自定义按钮
            CopyButtonReqDTO copyButtonReqDTO = new CopyButtonReqDTO();
            copyButtonReqDTO.setSource(new ButtonSourceDTO(ButtonSourceTypeEnum.APPLICATION_VIEW_BUTTON, view.getApplicationViewId(), view.getApplicationVersion()));
            copyButtonReqDTO.setTarget(new ButtonSourceDTO(ButtonSourceTypeEnum.APPLICATION_VIEW_BUTTON, copyView.getApplicationViewId(), copyView.getApplicationVersion()));
            copyButtonReqDTO.setUpdateSource(updateSource);
            applicationButtonService.copyButton(copyButtonReqDTO);
        });

        List<ApplicationView> deleted = target.stream()
                .filter(e -> !modifyIds.contains(e.getApplicationViewId()))
                .peek(e -> {
                    e.setIsDeleted(SwitchEnum.YES.getId());
                    // 筛选视图 - 删除筛选
                    if (ApplicationViewTypeEnum.FILTER.getId() == e.getViewType()) {
                        applicationFilterGroupService.deleteBySource(new FilterSourceDTO(FilterSourceTypeEnum.FILTER_VIEW_FILTER, e.getApplicationViewId()));
                    }
                })
                .collect(Collectors.toList());

        applicationLogService.saveAndCheck(this.baseMapper, ApplicationView::getApplicationViewId, deleted);
    }

    /**
     * 复制视图实体属性
     *
     * @param source 复制源
     * @param target 复制目标
     */
    private void copyViewProp(ApplicationView source, ApplicationView target) {
        target.setViewName(source.getViewName());
        target.setViewTitle(source.getViewTitle());
        target.setViewType(source.getViewType());
        target.setViewConfig(source.getViewConfig());
        target.setPosition(source.getPosition());
    }
}
